 /*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

 /**
 * Project  : EasyAvatar-Android
 * Package  : net.solosky.easyavatar.activity
 * File     : Friends.java
 * Author   : solosky < solosky772@qq.com >
 * Created  : Nov 12, 2011
 * License  : Apache License 2.0 
 */
package net.solosky.easyavatar.activity;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import net.solosky.easyavatar.R;
import net.solosky.easyavatar.api.ApiException;
import net.solosky.easyavatar.api.Avatar;
import net.solosky.easyavatar.api.Avatar.Scale;
import net.solosky.easyavatar.api.ErrorCode;
import net.solosky.easyavatar.api.Friend;
import net.solosky.easyavatar.api.FriendList;
import net.solosky.easyavatar.api.FriendProvider;
import net.solosky.easyavatar.api.OAuthFriendProvider;
import net.solosky.easyavatar.bean.AuthInfo;
import net.solosky.easyavatar.bean.Contact;
import net.solosky.easyavatar.bean.Match;
import net.solosky.easyavatar.bean.Match.MatchType;
import net.solosky.easyavatar.bean.ProviderMeta;
import net.solosky.easyavatar.bean.ProviderMeta.AuthType;
import net.solosky.easyavatar.utils.AsyncTask;
import net.solosky.easyavatar.utils.Globals;
import net.solosky.easyavatar.utils.MatchHelper;
import net.solosky.easyavatar.utils.TaskHelper;
import net.solosky.easyavatar.utils.Utils;
import net.solosky.easyavatar.utils.Views;
import net.solosky.easyavatar.view.ListOptionDialog;
import net.solosky.easyavatar.view.ListOptionDialog.ListOption;
import net.solosky.easyavatar.view.ListOptionDialog.OnListOptionClickListener;
import net.solosky.easyavatar.view.MatchExpandableListAdapter;

import org.scribe.model.Token;

import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.BaseExpandableListAdapter;
import android.widget.Button;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.OnChildClickListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.TextView;

/**
 * 
 * 好友列表，根据接口获取好友列表并自动匹配联系人设置头像
 *
 * @author solosky <solosky772@qq.com>
 *
 */
public class Friends extends Base implements OnClickListener,OnListOptionClickListener, OnChildClickListener {
	
	private static final int OPT_SELECT_CONTACT = 1;
	private static final int OPT_CANCEL_MATCH   = 2;
	private static final String MY_FRIENDS = "MyFriends";
	private static final String MAY_KNOWNS = "MayKnowns";
	
	private FriendProvider mFriendProvider;
	private ProviderMeta   mProviderMeta;
	private ProgressDialog mProgressDialog;
	private ExpandableListView mMatchListView;
	private MatchExpandableListAdapter mMatchAdapter;
	private MatchHelper    mMyFriendsMatchHelper;
	private MatchHelper    mMayKnownsMatchHelper;
	private MatchHelper    mMatchedMatchHelper;
	private TaskHelper mAsyncTaskHelper;
	private Friend			mMySelf;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		if(!checkInitilized() || !initFriendProvider()){ finish(); return;}
		
		setContentView(R.layout.ui_friends);
		setupUI();
		setTitle(mProviderMeta.getTitle());
		setupBackButton();
		
		mAsyncTaskHelper.addAsyncTask(new LoadingMyInfoTask(), null);
	}
	
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
		mAsyncTaskHelper.cancelAllTasks();
		mMyFriendsMatchHelper.clear();
		mMayKnownsMatchHelper.clear();
	}

	private boolean initFriendProvider(){
		mProviderMeta = Utils.getProviderMeta(getIntent().getStringExtra("provider.code"));
		if(Globals.ACTIVE_FRIEND_PROVIDER!=null 
				&& mProviderMeta.getAuthType()==AuthType.WEB){
			//是WEB方式认证时，由Login完成登录逻辑并把登录成功之后的对象放在全局变量G.ACTIVE_FRIEND_PROVIDER
			mFriendProvider = Globals.ACTIVE_FRIEND_PROVIDER;
			Globals.ACTIVE_FRIEND_PROVIDER = null;
		}else if(mProviderMeta.getAuthType()==AuthType.OAUTH
				&& mProviderMeta.getAuthInfo().isAuthorized()){
			//如果是OAuth方式认证，如果已经成功认证，直接构建接口对象
			try {
				Class<?> providerClass = Class.forName(mProviderMeta.getClazz());
				OAuthFriendProvider oauthProvider = (OAuthFriendProvider) providerClass.newInstance();
				AuthInfo authInfo = mProviderMeta.getAuthInfo();
				oauthProvider.createOAuthService(mProviderMeta.getAppKey(), 
						mProviderMeta.getAppSecret(), null);
				oauthProvider.setAccessToken(new Token(authInfo.getToken(), authInfo.getSecret()));
				oauthProvider.init();
				mFriendProvider = oauthProvider;
			} catch (Exception e) {
				e.printStackTrace();
				Views.showToast(R.string.err_provider_init_error);
				return false;
			}
		}else{
			//Views.showToast(R.string.err_invalid_params);
			return false;
		}
		
		mMyFriendsMatchHelper = new MatchHelper();
		mMayKnownsMatchHelper = new MatchHelper();
		mMatchedMatchHelper = new MatchHelper();
		mAsyncTaskHelper = new TaskHelper();
		
		mMyFriendsMatchHelper.setDefaultGroupTitle(Views.S(R.string.my_friends));
		mMayKnownsMatchHelper.setDefaultGroupTitle(Views.S(R.string.may_knowns));
		
		return true;
	}
	
	private void setupUI(){
		mProgressDialog = new ProgressDialog(this);
		mProgressDialog.setCancelable(true);
		mProgressDialog.setIndeterminate(true);
		//mProgressDialog.setOnCancelListener(this);
		
		mMatchListView = (ExpandableListView) findViewById(R.id.elv_friends);
		mMatchListView.setGroupIndicator(null);
		mMatchAdapter = new MatchExpandableListAdapter(this);
		mMatchAdapter.setMatchHelper(mMyFriendsMatchHelper);
		mMatchListView.setAdapter(mMatchAdapter);
		mMatchListView.setOnChildClickListener(this);
		
		int[] tabRadioIds = {R.id.rd_my_friends, R.id.rd_may_knowns, R.id.rd_matched_friends};
		for(int radioId: tabRadioIds){
			RadioButton rd = (RadioButton) findViewById(radioId);
			rd.setOnClickListener(this);
		}
		
		setRightButton(R.string.save, this);
		Button bt = (Button) findViewById(R.id.bt_set_my_avatar);
		bt.setOnClickListener(this);
	}
	
	@Override
	public void onClick(View v) {
		switch(v.getId()){
			case R.id.rd_my_friends:
				mMatchAdapter.setMatchHelper(mMyFriendsMatchHelper);
				mMatchAdapter.notifyDataSetChanged();
				if(!mMyFriendsMatchHelper.hasFriend()){
					new LoadingFriendListTask().execute(null);
				}
				break;
					
			case R.id.rd_may_knowns:
				mMatchAdapter.setMatchHelper(mMayKnownsMatchHelper);
				mMatchAdapter.notifyDataSetChanged();
				if(!mMayKnownsMatchHelper.hasFriend()){
					new LoadingMayKnownsTask().execute(null);
				}
				break;
					
			case R.id.rd_matched_friends:
				mMatchAdapter.setMatchHelper(mMatchedMatchHelper);
				mMatchAdapter.notifyDataSetChanged();
				break;
				
			case R.id.bt_title_right:
				//需要过滤掉好友下载头像失败或者没有头像的匹配对象
				List<Match> pendingMatches = new ArrayList<Match>();
				pendingMatches.addAll(mMyFriendsMatchHelper.getAreadyMatchedList());
				pendingMatches.addAll(mMayKnownsMatchHelper.getAreadyMatchedList());
				Iterator<Match> it = pendingMatches.iterator();
				while(it.hasNext()){
					Match match = it.next();
					if(match.getFriend().getAvatar().getTag()==null){
						it.remove();
					}
				}
				if(pendingMatches.size()>0){
					final Match[] matchArray = new Match[pendingMatches.size()];
					pendingMatches.toArray(matchArray);
					Views.showConfirm(Views.S(R.string.info),Views.S(R.string.cfm_update_contact_photos), 
						new DialogInterface.OnClickListener() {
							public void onClick(DialogInterface dialog, int which) {
								new updatingContactAvatarTask().execute(matchArray);
							}
						}, null);
				}
				break;
				
				
			case R.id.bt_set_my_avatar:
				Contact my = Globals.CONTACT_MANAGER.getMySelfContact(Friends.this);
				if(my!=null){
					new UpdatingMyAvatarTask().execute(null);
				}else{
					Views.showToast(R.string.hint_set_my_mobile);
				}
				break;
		}
	}

	@Override
	public boolean onChildClick(ExpandableListView parent, View v,
			int groupPosition, int childPosition, long id) {
		BaseExpandableListAdapter ad = (BaseExpandableListAdapter) parent.getExpandableListAdapter();
		Match match = (Match) ad.getChild(groupPosition, childPosition);
		List<ListOption> options  = new ArrayList<ListOption>();
		options.add(new ListOption(OPT_SELECT_CONTACT, Views.S(R.string.opt_select_contact), null));
		if(match.getContact()!=null){
			options.add(new ListOption(OPT_CANCEL_MATCH, Views.S(R.string.opt_cancel_match), null));
		}
		new ListOptionDialog(this, (ListView) parent, groupPosition, childPosition, this)
		.setListOptions(options)
		.setTitle(match.getFriend().getDisplay())
		.show();
		return false;
	}


	@Override
	public void onClick(ListOptionDialog dialog, ListOption option) {
		Match match  = (Match) dialog.getItemData();
		switch(option.getId()){
		case OPT_CANCEL_MATCH:
			mMayKnownsMatchHelper.cancelMatch(match.getFriend().getFid());
			mMyFriendsMatchHelper.cancelMatch(match.getFriend().getFid());	//懒得判断了，直接调用两次
			updateMatchResult();
			break;
			
		case OPT_SELECT_CONTACT:
			Intent intent = new Intent(this, Contacts.class);
			intent.putExtra("friend.fid", match.getFriend().getFid());
			startActivityForResult(intent, 0);
			break;
		}
	}
	
	
	
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if(resultCode==RESULT_OK){
			String fid = data.getStringExtra("friend.fid");
			String cid = data.getStringExtra("contact.cid");
			
			Contact contact = Globals.CONTACT_MANAGER.findContactById(cid);
			MatchHelper curHelper = mMyFriendsMatchHelper;
			Match   match   = mMyFriendsMatchHelper.findMatchByFriendId(fid);
			if(match==null) {
				match = mMayKnownsMatchHelper.findMatchByFriendId(fid);
				curHelper = mMayKnownsMatchHelper;
			}
			
			if(match!=null && contact!=null){
				match.setContact(contact);
				match.setType(MatchType.USER);
				curHelper.updateMatch(match);
				updateMatchResult();
			}
		}
	}


	/**
	 * 更新匹配结果
	 */
	private void updateMatchResult(){
		mMatchedMatchHelper.reset();
		mMatchedMatchHelper.addGroup(MY_FRIENDS, Views.S(R.string.my_friends));
		mMatchedMatchHelper.addGroup(MAY_KNOWNS, Views.S(R.string.may_knowns));
		
		mMatchedMatchHelper.addMatches(MY_FRIENDS, mMyFriendsMatchHelper.getAreadyMatchedList());
		mMatchedMatchHelper.addMatches(MAY_KNOWNS, mMayKnownsMatchHelper.getAreadyMatchedList());
		
		mMatchAdapter.notifyDataSetChanged();
		
	}
	
	private void startLoadFriendAvatars(FriendList friendList, boolean isMyFriends){
		Iterator<Friend> it = friendList.getFriends().iterator();
		while(it.hasNext()){
			Friend friend = it.next();
			Friend[] params = {friend};
			//mAsyncTaskHelper.excuteAsyncTask(new LoadingFriendAvatarTask(), params);
			if(isMyFriends){
				new LoadingFriendAvatarTask().execute(params);
			}else{
				new LoadingFriendAvatarTask().execute(params);
			}
		}
	}
	
	/***
	 * 获取个人信息任务
	 */
	class LoadingMyInfoTask extends AsyncTask<String, String, ErrorCode>{
		@Override
		protected void onPostExecute(ErrorCode result) {
			if(result==ErrorCode.NO_ERROR){
				TextView tv = (TextView) findViewById(R.id.tv_self_name);
				tv.setText(mMySelf.getDisplay());
				tv = (TextView) findViewById(R.id.tv_self_intro);
				tv.setText(mProviderMeta.getTitle());
				
				Avatar my = mMySelf.getAvatar();
				ImageView iv = (ImageView) findViewById(R.id.iv_self_avatar);
				Bitmap bm = BitmapFactory.decodeStream(new ByteArrayInputStream(my.getData()));
				my.setTag(bm);
				my.setData(null); //减少内存使用
				iv.setImageBitmap(bm);
				
				//启动另一个获取好友列表的任务
				mAsyncTaskHelper.addAsyncTask(new LoadingFriendListTask(), null);

			}else{
				Views.showMessage(getString(R.string.info), result.toString(), null);
			}
		}

		@Override
		protected void onPreExecute() {
			mProgressDialog.show();
			mProgressDialog.setMessage(getResources().getString(R.string.st_loading_my_info));
		}

		@Override
		protected ErrorCode doInBackground(String... params) {
			try {
				mMySelf = mFriendProvider.retireMyInfo();
				mFriendProvider.retireMyAvatar(mMySelf, Scale.LARGE);
				return ErrorCode.NO_ERROR;
			} catch (ApiException e) {
				return e.getErrorCode();
			} catch (IOException e) {
				return ErrorCode.IO_ERROR;
			}
		}
	}
	
	/***
	 * 获取好友列表任务
	 */
	private class LoadingFriendListTask extends AsyncTask<String, String, ErrorCode>{
		private FriendList mFriendList;
		@Override
		protected void onPostExecute(ErrorCode result) {
			mProgressDialog.hide();
			if(result==ErrorCode.NO_ERROR){
				updateMatchResult();
				startLoadFriendAvatars(mFriendList, true);
			}else{
				Views.showMessage(getString(R.string.info), result.toString(), null);
			}
		}

		@Override
		protected void onPreExecute() {
			mProgressDialog.show();
			mProgressDialog.setMessage(getResources().getString(R.string.st_loading_my_friends));
		}

		@Override
		protected ErrorCode doInBackground(String... params) {
			try {
				mFriendList = mFriendProvider.retireMyFriends(mMyFriendsMatchHelper.nextIndex());
				mMyFriendsMatchHelper.appendFriendList(mFriendList);
				return ErrorCode.NO_ERROR;
			} catch (ApiException e) {
				return e.getErrorCode();
			} catch (IOException e) {
				return ErrorCode.IO_ERROR;
			}
		}
	}
	
	/***
	 * 获取好友列表任务
	 */
	private class LoadingMayKnownsTask extends AsyncTask<String, String, ErrorCode>{
		private FriendList mFriendList;
		@Override
		protected void onPostExecute(ErrorCode result) {
			mProgressDialog.hide();
			if(result==ErrorCode.NO_ERROR){
				updateMatchResult();
				startLoadFriendAvatars(mFriendList, false);
			}else{
				Views.showMessage(getString(R.string.info), result.toString(), null);
			}
		}

		@Override
		protected void onPreExecute() {
			mProgressDialog.show();
			mProgressDialog.setMessage(getResources().getString(R.string.st_loading_may_knows));
		}

		@Override
		protected ErrorCode doInBackground(String... params) {
			try {
				mFriendList = mFriendProvider.retireMayKnowns(mMayKnownsMatchHelper.nextIndex());
				mMayKnownsMatchHelper.appendFriendList(mFriendList);
				return ErrorCode.NO_ERROR;
			} catch (ApiException e) {
				return e.getErrorCode();
			} catch (IOException e) {
				return ErrorCode.IO_ERROR;
			}
		}
	}
	
	/**
	 * 获取好友头像任务
	 */
	private class LoadingFriendAvatarTask extends AsyncTask<Friend, String, ErrorCode>{
		private Friend mFriend;
		@Override
		protected void onPostExecute(ErrorCode result) {
			if(result==ErrorCode.NO_ERROR){
				mMatchAdapter.notifyDataSetChanged();
			}else if(result==ErrorCode.NO_AVATAR){
			}else{
				Views.showToast(String.format(getResources()
						.getString(R.string.ret_load_avatar_failed),
						mFriend.getDisplay(), mFriend.getFid()));
			}
		}
		@Override
		protected ErrorCode doInBackground(Friend... params) {
			try {
				mFriend = params[0];
				Avatar avatar = mFriendProvider.retireFriendAvatar(mFriend, Scale.SMAILL);
				Bitmap bm = BitmapFactory.decodeStream(new ByteArrayInputStream(avatar.getData()));
				avatar.setTag(bm);
				avatar.setData(null); //减少内存使用
				Utils.dout("loaded friend avatar: "+mFriend.getDisplay()+"("+mFriend.getFid()+")");
				return ErrorCode.NO_ERROR;
			} catch (ApiException e) {
				return e.getErrorCode();
			} catch (IOException e) {
				return ErrorCode.IO_ERROR;
			}
		}
	}
	
	/**
	 * 设置联系人头像任务
	 */
	private class updatingContactAvatarTask extends  AsyncTask<Match, Message, Message>{
		@Override
		protected void onPreExecute() {
			mProgressDialog = new ProgressDialog(Friends.this); 
			mProgressDialog.setMessage(getResources().getString(R.string.st_updating_contact_avatars));
			mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
			mProgressDialog.show();
		}

		@Override
		protected void onPostExecute(Message msg) {
			mProgressDialog.hide();
			mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
			mMatchAdapter.notifyDataSetChanged();
		}

		@Override
		protected Message doInBackground(Match... params) {
			int updated = 0;
			publishProgress(new Message[]{Views.M(updated, params.length, "")});
			
			for(Match match : params){
				if(!isCancelled()){
					try {
						Avatar avatar = mFriendProvider.retireFriendAvatar(match.getFriend(), Scale.LARGE);
						Globals.CONTACT_MANAGER.setContactPhoto(Friends.this, avatar.getData(), Long.parseLong(match.getContact().getId()), true);
						avatar.setData(null);
						match.getContact().setHead((Bitmap) match.getFriend().getAvatar().getTag());
					} catch (Exception e) {
						Views.showToast(String.format(getResources()
								.getString(R.string.ret_load_avatar_failed),
								match.getFriend().getDisplay(), match.getFriend().getFid()));
					}
					updated++;
					
					publishProgress(new Message[]{Views.M(updated, params.length, match.getContact().getName())});
				}else{
					return Views.M(updated, params.length, ErrorCode.CANCELED);
				}
			}
			return Views.M(updated, params.length, ErrorCode.NO_ERROR);
		}

		@Override
		protected void onProgressUpdate(Message... values) {
			Message msg = values[0];
			mProgressDialog.setProgress(msg.arg1);
			mProgressDialog.setMax(msg.arg2);
			mProgressDialog.setMessage(String.format(Views.S(R.string.st_updating_contact_avatars_s), msg.obj));
		}
	}
	
	/**
	 * 设置自己头像任务
	 */
	private class UpdatingMyAvatarTask extends AsyncTask<Void, String, ErrorCode>{
		@Override
		protected void onPreExecute() {
			mProgressDialog = new ProgressDialog(Friends.this); 
			mProgressDialog.setMessage(getResources().getString(R.string.st_updating_my_avatar));
			mProgressDialog.show();
		}

		@Override
		protected void onPostExecute(ErrorCode result) {
			mProgressDialog.hide();
			if(result==ErrorCode.NO_ERROR){
				Views.showToast(R.string.ret_update_my_avatar_sucess);
			}else if(result==ErrorCode.NO_AVATAR){
			}else{
				Views.showMessage(getString(R.string.info), result.toString(), null);
			}
		}
		@Override
		protected ErrorCode doInBackground(Void... params) {
			try {
				Contact my = Globals.CONTACT_MANAGER.getMySelfContact(Friends.this);
				Avatar avatar = mFriendProvider.retireMyAvatar(mMySelf, Scale.LARGE);
				Globals.CONTACT_MANAGER.setContactPhoto(Friends.this, avatar.getData(), Long.parseLong(my.getId()), true);
				avatar.setData(null);
				my.setHead((Bitmap) mMySelf.getAvatar().getTag());
				return ErrorCode.NO_ERROR;
			} catch (ApiException e) {
				return e.getErrorCode();
			} catch (IOException e) {
				return ErrorCode.IO_ERROR;
			}
		}
	}
}
